﻿
Imports std

Public Class switch
    Inherits sentence

    Public Const switch As String = "switch"
    Public Const [select] As String = "select"
    Public Const by As String = "by"
    Public Const casesStart As Char = character.leftBrace
    Public Const casesEnd As Char = character.rightBrace

    Protected Friend Shared Shadows Function _isMeaningfulMark(ByVal c As Char) As Boolean
        Return isCasesStart(c) OrElse isCasesEnd(c) OrElse [case]._isMeaningfulMark(c)
    End Function

    Private Shared Function isCasesStart(ByVal c As Char) As Boolean
        Return c = casesStart
    End Function

    Private Shared Function isCasesEnd(ByVal c As Char) As Boolean
        Return c = casesEnd
    End Function

    Private Shared Function switchstart(ByVal s As String, ByVal index As Int64, ByRef inc As Int64) As Boolean
        If strsame(s, index, switch, 0, strlen(switch)) Then
            inc = strlen(switch)
            Return True
        ElseIf strsame(s, index, [select], 0, strlen([select])) Then
            inc = strlen([select])
            Return True
        Else
            Return False
        End If
    End Function

    Private Shared Function isby(ByVal s As String, ByVal index As Int64, ByRef inc As Int64) As Boolean
        If strsame(s, index, by, 0, strlen(by)) Then
            inc = strlen(by)
            Return True
        Else
            Return False
        End If
    End Function

    Private Class [case]
        Inherits iScript
        Implements iInvokeableWithParameter(Of parameter)

        Public Const [case] As String = "case"
        Public Const conditionStart As Char = character.leftBracket
        Public Const conditionEnd As Char = character.rightBracket
        Public Const conditionSeparator As Char = character.semicolon

        Private parameters As parameters_list2 = Nothing
        Private paragraph As paragraph = Nothing

        Protected Friend Shared Function _isMeaningfulMark(ByVal c As Char) As Boolean
            Return isConditionStart(c) OrElse isConditionEnd(c) OrElse isConditionSeparator(c)
        End Function

        Private Sub New(ByVal ps As parameters_list2, ByVal p As paragraph)
            parameters = ps
            paragraph = p
        End Sub

        Public Class parameter
            Public input As bare_variable = Nothing
            Public funcname As String = Nothing
            Public match As Boolean = False
        End Class

        Private Function invoke(ByVal ctx As context, ByVal input As bare_variable, _
                                ByVal funcname As String, ByRef match As Boolean) As Boolean
            Dim pt As parameters_t = Nothing
            pt = New parameters_t()
            pt.push_back(make_pair(Of String, bare_variable)(Nothing, input))
            pt.push_back(make_pair(Of String, bare_variable)(Nothing, Nothing))

            Dim i As Int64
            For i = 0 To parameters.size() - 1
                Dim v As bare_variable = Nothing
                If parameters.at(i, v, ctx) Then
                    pt(1).second = v
                    Dim comp As bare_variable = Nothing
                    If ctx.invoke(funcname, convertor.cast(Of iParametersWithMapping)(pt), comp) Then
                        If comp.true() Then
                            match = True
                            Return paragraph.invoke(ctx)
                        End If
                    Else
                        Return False
                    End If
                Else
                    Return False
                End If
            Next

            match = False
            Return True
        End Function

        Protected Overrides Function invokeImpl(Of T)(ByVal ctx As context, ByRef obj As T) As Boolean
            Dim p As parameter = Nothing
            p = convertor.cast(Of parameter)(obj)
            Return invoke(ctx, p.input, p.funcname, p.match)
        End Function

        Public Function invoke(ByVal ctx As context, ByVal p As parameter) As Boolean _
                              Implements iInvokeableWithParameter(Of parameter).invoke
            Return invokebase(ctx, p)
        End Function

        Protected Overrides Sub setsource(ByVal script As String, ByVal start As Int64, ByVal [end] As Int64)
            setsourceImpl([case] + _
                          conditionStart + parameters.scriptSource() + conditionEnd + _
                          paragraph.scriptSource(), _
                          start, [end])
        End Sub

        Private Shared Function isConditionStart(ByVal c As Char) As Boolean
            Return c = conditionStart
        End Function

        Private Shared Function isConditionEnd(ByVal c As Char) As Boolean
            Return c = conditionEnd
        End Function

        Private Shared Function isConditionSeparator(ByVal c As Char) As Boolean
            Return c = conditionSeparator
        End Function

        Private Shared Function casestart(ByVal s As String, ByVal index As Int64, ByRef inc As Int64) As Boolean
            If strsame(s, index, [case], 0, strlen([case])) Then
                inc = strlen([case])
                Return True
            Else
                Return False
            End If
        End Function

        Private Shared Function parseImpl(ByVal input As String, ByRef index As Int64, _
                                          ByRef output As [case]) As Boolean
            If token(input, index, Nothing, AddressOf casestart, AddressOf [false]) Then
                token(input, index, Nothing, AddressOf isConditionStart, AddressOf [false])
                Dim ps As parameters_list2 = Nothing
                If parameters_list2.parse(input, index, ps) Then
                    token(input, index, Nothing, AddressOf isConditionEnd, AddressOf [false])
                    Dim para As paragraph = Nothing
                    If paragraph.parse(input, index, para) Then
                        output = New [case](ps, para)
                        Return True
                    End If
                End If
            End If

            Return False
        End Function

        Public Shared Function parse(ByVal input As String, ByRef index As Int64, ByRef output As [case]) As Boolean
            Return parsebase(input, index, output, AddressOf parseImpl)
        End Function
    End Class

    Private Class [default]
        Inherits iScript
        Implements iInvokeable

        Public Const [default] As String = "default"

        Private paragraph As paragraph = Nothing

        Private Sub New(ByVal p As paragraph)
            paragraph = p
        End Sub

        Protected Overrides Function invokeImpl(ByVal ctx As context) As Boolean
            Return paragraph.invoke(ctx)
        End Function

        Public Function invoke(ByVal ctx As context) As Boolean Implements iInvokeable.invoke
            Return invokebase(ctx)
        End Function

        Protected Overrides Sub setsource(ByVal script As String, ByVal start As Int64, ByVal [end] As Int64)
            setsourceImpl([default] + character.blank + paragraph.scriptSource(), start, [end])
        End Sub

        Private Shared Function defaultstart(ByVal s As String, ByVal index As Int64, ByRef inc As Int64) As Boolean
            If strsame(s, index, [default], 0, strlen([default])) Then
                inc = strlen([default])
                Return True
            Else
                Return False
            End If
        End Function

        Private Shared Function parseImpl(ByVal input As String, ByRef index As Int64, _
                                          ByRef output As [default]) As Boolean
            Dim para As paragraph = Nothing
            If token(input, index, Nothing, AddressOf defaultstart, AddressOf [false]) AndAlso _
               paragraph.parse(input, index, para) Then
                output = New [default](para)
                Return True
            End If

            Return False
        End Function

        Public Shared Function parse(ByVal input As String, ByRef index As Int64, ByRef output As [default]) As Boolean
            Return parsebase(input, index, output, AddressOf parseImpl)
        End Function
    End Class

    Private value As value = Nothing
    Private byname As String = Nothing
    Private cases As vector(Of [case]) = Nothing
    Private def As [default] = Nothing

    Private Sub New(ByVal v As value, ByVal b As String, ByVal cs As vector(Of [case]), ByVal d As [default])
        value = v
        byname = b
        cases = cs
        def = d
    End Sub

    Protected Overrides Sub setsource(ByVal script As String, ByVal start As Int64, ByVal [end] As Int64)
        setsourceImpl([select] + character.blank + value.scriptSource(), start, [end])
    End Sub

    Protected Overrides Function invokeImpl(ByVal ctx As context) As Boolean
        Dim bv As bare_variable = Nothing
        If value.invoke(ctx, bv) Then
            Dim p As [case].parameter = Nothing
            p = New [case].parameter()
            p.funcname = ifoper(isemptystring(byname), internalFunctions.equal.functionName, byname)
            p.input = bv
            p.match = False
            Dim i As Int64
            For i = 0 To cases.size() - 1
                If Not cases(i).invoke(ctx, p) Then
                    Return False
                ElseIf p.match Then
                    Exit For
                End If
            Next

            Return i < cases.size() OrElse def.invoke(ctx)
        Else
            Return False
        End If
    End Function

    Private Shared Function parseImpl(ByVal input As String, ByRef index As Int64, ByRef output As switch) As Boolean
        If token(input, index, Nothing, AddressOf switchstart, AddressOf [false]) Then
            Dim value As value = Nothing
            If value.parse(input, index, value) Then
                Dim byname As String = Nothing
                If Not token(input, index, Nothing, AddressOf isby, AddressOf [false]) OrElse _
                   function_name_defination.parse(input, index, byname) Then
                    Dim hasCasesStart As Boolean
                    hasCasesStart = token(input, index, Nothing, AddressOf isCasesStart, AddressOf [false])
                    Dim cases As vector(Of [case]) = Nothing
                    cases = New vector(Of [case])()
                    Dim def As [default] = Nothing
                    Dim c As [case] = Nothing
                    While True
                        If [case].parse(input, index, c) Then
                            cases.push_back(c)
                        ElseIf Not [default].parse(input, index, def) Then
                            Exit While
                        End If
                    End While
                    If Not hasCasesStart OrElse _
                       token(input, index, Nothing, AddressOf isCasesEnd, AddressOf [false]) Then
                        output = New switch(value, byname, cases, def)
                        Return True
                    End If
                End If
            End If
        End If

        Return False
    End Function

    Public Shared Shadows Function parse(ByVal input As String, ByRef index As Int64, _
                                         ByRef output As switch) As Boolean
        Return parsebase(input, index, output, AddressOf parseImpl)
    End Function
End Class